home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
COMMS
/
C011.ZIP
/
LAR.C
< prev
next >
Wrap
Text File
|
1990-01-19
|
17KB
|
724 lines
/********************************************************************
* C Users Group (U.K) C Source Code Library File CUGLIB.011 *
* Inquiries to: M. Houston, 36 Whetstone Clo. Farquhar Rd. *
* Edgbaston, Birmingham B15 2QN ENGLAND *
********************************************************************
* File name: lar.c
* Program name: lar
* Source of file: The Public Domain Software Library.
* Purpose: LU format library manager
* Changes: <who what when & why major changes have been made>
********************************************************************/
/*
* Lar - LU format library file maintainer
* by Stephen C. Hemminger
* linus!sch or sch @Mitre-Bedford MA
*
* Lattice version T. Jennings 1 Dec 83
*
* DESCRIPTION
* Lar is a program to manipulate CP/M LU format libraries.
* The original CP/M library program LU is the product
* of Gary P. Novosielski. The primary use of lar is to combine several
* files together for upload/download to a personal computer.
*
* Usage: lar key library [files] ...
*
* Key functions are:
* u - Update, add files to library (also creates new libraries)
* t - Table of contents
* e - Extract files from library
* p - Print files in library
* d - Delete files in library
* r - Reorganize library
*
* EXAMPLES:
* lar t foo.lbr list all files in FOO.LBR
* lar e foo.lbr 1.c 2.c extract files 1.c, 2.c from FOO.LBR
* lar p foo.lbr 1.c display 1.c from FOO.LBR
* lar u foo.lbr 1.c 2.c 3.c add or replace files in FOO.LBR
*
* When creating a new library, you will be prompted for the maximum
* number of entries it can contain. Assuming NEW.LBR doen't exist ...
* lar u new.lbr create an empty library
* lar u new.lbr a.c,b.c,d.c create NEW.LBR, add files.
*
* The Reorganize option causes <lbrfile>.tmp to be created, and
* the contents of the old library to be copied into it.
*
* This program is public domain software, no warranty intended or
* implied.
*
*
* PORTABILITY
* The original version by Stephan C. Hemminger was set up for
* Version 7 UNIX, and was not useable as is. It has been hacked
* to fit the Lattice C compiler for MSDOS and CP/M-86. The basic
* problems were: fread() and fwrite() incompatibility, no
* text/binary differntiation problem in MSDOS, structure alignment
* problems, Lattice vs. UNIX vs. BDS. Lattice does not gaurentee
* structure element alignment (i.e. an int after a char is not
* necessarily the next byte address) and therefore there is a serious
* kludge in the structure definition for the library.
*
* Also, I have made random changes to the source merely to reflect
* my programming taste; the original code was quite good. I have also
* changed the wording of some errors, etc more in line with the current
* flavor of messages in the micro environment. The original Verbose
* flag option was removed, and made the default. No need to suppress
* what few messages and text there is.
*
* As mentioned before, ther is no problem with text or binary files;
* they are treated identically. Control-Z characters are added to the
* end of all files to round it up to a multiple of 128 bytes.
*
* Note that all files are kept as multiples of 128 bytes, to be
* compatible with the CP/M utility LU. This may present a problem
* with certain data files, but will be OK for text and .COM files
* anyways, and probably most other files.
*
* NOTES ON MSDOS VERSION
* There is an annoying problem with this program when run under MSDOS.
* If for some reason an update should fail (disk full, not enough slots)
* the file will not be closed, and therefore there will be orphan data
* blocks hanging around. Do CHKDSK\F to fix this. The problem is with
* the use of the error() function, which is called throughout and just
* exits to DOS after reporting the error, with out closing the file.
* Check your .LBR file after this happens; it may be bad. Do a reorganize
* to fix if necessary.
*
* To compensate for this, I also fixed a bug in the original version. If
* an empty library was created, it could not be used. One had to be
* created with at least one file. The problem was that the directory-
* getter function (getdir) always read 16 bytes more than the actual
* size of the directory; this was OK if there was files in the library.
*
* * Unix is a trademark of Bell Labs.
* ** CP/M is a trademark of Digital Research.
*/
#include <stdio.h>
#include <ctype.h>
/* There is no tell(), but lseek() does the same thing. For some reason seek()
is called lseek. Fix this minor annoyance. */
long lseek();
#define tell(f) lseek(f,0L,1)
#define seek lseek
/* Library file status values: */
#define ACTIVE 0
#define UNUSED 0xff
#define DELETED 0xfe
#define CTRLZ 0x1a
#define MAXFILES 256
#define SECTOR 128
#define DSIZE (sizeof(struct ludir))
#define SLOTS_SEC (SECTOR/DSIZE)
#define equal(s1, s2) ( strcmp(s1,s2) == 0 )
#define false 0
#define true 1
#define bool int
/* Globals */
char *fname[MAXFILES];
bool ftouched[MAXFILES];
/* This bullshit (or something like it) is necessary because the byte order
of structure elements is not garenteed in Lattice C, i.e. an INT right after
an CHAR is not necessarily &( CHAR + 1), i.e. there's a fill byte after the
CHAR to put it on a word boundary.
This is incredibly gross, and forces proper alignment for Lattice ONLY !!! */
struct ludir { /* internal dir. stucture, 32 bytes */
char l_l[12]; /* 12 byte filename: */
#define l_stat l_l[0] /* status of file, */
#define l_name l_l[1] /* filename, */
#define l_ext l_l[9] /* extention, */
int l_off; /* offset in library, */
int l_len; /* length of file, */
int l_fill[8]; /* 16 byte filler, */
} ldir[MAXFILES];
int errcnt, nfiles, nslots;
char *getname(), *sprintf();
main (argc, argv)
int argc;
char **argv;
{
char *flagp;
char *aname;
if (argc < 3)
help ();
aname = argv[2]; /* name of LBR file, */
filenames (argc, argv);
switch (tolower(*argv[1])) {
case 'u':
update(aname);
break;
case 't':
table(aname);
break;
case 'e':
extract(aname);
break;
case 'p':
print(aname);
break;
case 'd':
delete(aname);
break;
case 'r':
reorg(aname);
break;
break;
default:
help();
}
exit();
}
/* print error message and exit */
help () {
printf ("Usage: LAR [utepdr] library [files] ...\n");
printf ("Functions are:\n\tu - Update, add files to library\n");
printf ("\tt - Table of contents\n");
printf ("\te - Extract files from library\n");
printf ("\tp - Print files in library\n");
printf ("\td - Delete files in library\n");
printf ("\tr - Reorganize library\n");
exit (1);
}
error (str)
char *str;
{
printf ("LAR: %s\n", str);
exit (1);
}
cant (name)
char *name;
{
printf ("%s: File open error\n", name);
exit (1);
}
/* Get file names, check for dups, and initialize */
filenames (ac, av)
char **av;
{
register int i, j;
errcnt = 0;
for (i = 0; i < ac - 3; i++) {
fname[i] = av[i + 3];
ftouched[i] = false;
if (i == MAXFILES)
error ("Too many file names.");
}
fname[i] = NULL;
nfiles = i;
for (i = 0; i < nfiles; i++)
for (j = i + 1; j < nfiles; j++)
if (equal (fname[i], fname[j])) {
printf ("%s", fname[i]);
error (": duplicate file name");
}
}
table (lib)
char *lib;
{
int lfd;
register int i, total;
int active = 0, unused = 0, deleted = 0;
char *uname;
if ((lfd= open(lib,0x8002)) == -1)
cant (lib);
getdir (lfd);
total = ldir[0].l_len;
printf("Name Index Length (sectors)\n");
printf("Directory %4u %6u\n", total, total);
for (i = 1; i < nslots; i++)
switch(ldir[i].l_stat) {
case ACTIVE:
active++;
uname = getname(&ldir[i].l_name, &ldir[i].l_ext);
total += ldir[i].l_len;
printf ("%-12s %4u %7u\n", uname,ldir[i].l_off,ldir[i].l_len);
break;
case UNUSED:
unused++;
break;
default:
deleted++;
}
printf("-----------------------------\n");
printf("Total sectors %7u\n", total);
printf("\nLibrary %s has %u slots, %u deleted, %u active, %u unused\n",
lib, nslots, deleted, active, unused);
close (lfd);
not_found ();
}
getdir (f)
int f;
{
int cnt;
seek(f,0L,0);
if (read(f,&ldir[0],DSIZE) != DSIZE) /* read 1st entry to find */
error ("No directory\n"); /* number of slots, */
nslots = ldir[0].l_len * SLOTS_SEC;
cnt= DSIZE * (nslots - 1); /* already read one slot, */
if (read(f,&ldir[1],cnt) != cnt)
error ("Can't read directory - is it a library?");
}
putdir (f)
int f;
{
seek(f,0L,0);
if (write(f,&ldir,nslots * DSIZE) != (nslots * DSIZE))
error ("Can't write directory - library may be botched");
}
initdir (f)
int f;
{
register int i;
int numsecs;
char line[80];
for (;;) {
cprintf ("Number of slots to allocate: ");
getstring(line);
cprintf("\r\n");
nslots = atoi (line);
if (nslots < 1)
printf ("Must have at least one!\n");
else if (nslots > MAXFILES)
printf ("Too many slots\n");
else
break;
}
numsecs = nslots / SLOTS_SEC;
nslots = numsecs * SLOTS_SEC;
for (i = 0; i < nslots; i++) {
ldir[i].l_stat= UNUSED;
blank_fill(&ldir[i].l_name,8);
blank_fill(&ldir[i].l_ext,3);
}
ldir[0].l_stat = ACTIVE;
ldir[0].l_len= numsecs;
putdir (f);
}
/* Fill an array with blanks, no trailing null. */
blank_fill(s,n)
char *s;
int n;
{
while (n--) *s++= ' ';
}
/* convert nm.ex to a Unix style string */
char *getname (nm, ex)
char *nm, *ex;
{
static char namebuf[14];
int i,j;
for (i= 0; (i < 8) && (nm[i] != ' '); i++)
namebuf[i]= tolower(nm[i]);
j= i;
namebuf[j++]= '.';
for (i= 0; (i < 3) && (ex[i] != ' '); i++)
namebuf[j++]= tolower(ex[i]);
namebuf[j]= '\0';
return namebuf;
}
putname (cpmname, unixname)
char *cpmname, *unixname;
{
cvt_to_fcb(unixname,cpmname);
}
/* filarg - check if name matches argument list */
filarg (name)
char *name;
{
register int i;
if (nfiles <= 0)
return 1;
for (i = 0; i < nfiles; i++)
if (equal (name, fname[i])) {
ftouched[i] = true;
return 1;
}
return 0;
}
not_found () {
register int i;
for (i = 0; i < nfiles; i++)
if (!ftouched[i]) {
printf ("%s: not in library.\n", fname[i]);
errcnt++;
}
}
extract(name)
char *name;
{
getfiles(name, false);
}
print(name)
char *name;
{
getfiles(name, true);
}
getfiles (name, pflag)
char *name;
bool pflag;
{
int lfd, ofd;
register int i;
char *unixname;
if ((lfd= open(name,0x8002)) == -1)
cant (name);
getdir (lfd);
for (i = 1; i < nslots; i++) {
if(ldir[i].l_stat != ACTIVE)
continue;
unixname = getname (&ldir[i].l_name, &ldir[i].l_ext);
if (!filarg (unixname))
continue;
printf("Extracting %s\n", unixname);
if (pflag)
ofd= open("CON",0x8002);
else
ofd= creat(unixname,0x8002);
if (ofd == -1) {
printf (" - can't create output file\n");
errcnt++;
}
else {
seek (lfd, (long) ldir[i].l_off * SECTOR,0);
acopy (lfd, ofd, ldir[i].l_len);
if (!pflag)
close (ofd);
}
}
close (lfd);
not_found ();
}
acopy (fdi, fdo, nsecs)
int fdi, fdo;
unsigned nsecs;
{
char buf[SECTOR];
while( nsecs-- != 0) {
if (read(fdi,buf,SECTOR) != SECTOR)
error("Can't read");
if (write(fdo,buf,SECTOR) != SECTOR)
error ("write error (acopy)");
}
}
update (name)
char *name;
{
int lfd;
register int i;
if ((lfd = open (name,0x8002)) == -1) {
if ((lfd = creat(name, 2)) == -1)
cant (name);
initdir (lfd);
/* We shouldnt have to do this, but writes to the (new) file fail otherwise. */
close(lfd); /* close it, */
lfd= open(name,0x8002); /* reopen it, */
}
getdir (lfd); /* read directory, */
for (i = 0; (i < nfiles) && (errcnt == 0); i++)
addfil (fname[i], lfd);
if (errcnt != 0)
printf ("fatal errors - last file may be bad\n");
putdir (lfd);
close (lfd);
}
addfil (name, lfd)
char *name;
int lfd;
{
int ifd;
register int secoffs, numsecs;
register int i;
if ((ifd= open(name,0x8002)) == -1) {
printf ("%s: can't find to add\n",name);
errcnt++;
return;
}
for (i = 0; i < nslots; i++) {
if (equal( getname (&ldir[i].l_name, &ldir[i].l_ext), name) ) {
printf("Updating existing file %s\n",name);
break;
}
if (ldir[i].l_stat != ACTIVE) {
printf("Adding new file %s\n",name);
break;
}
}
if (i >= nslots) {
printf("Can't add %s, library is full\n",name);
errcnt++;
return;
}
ldir[i].l_stat = ACTIVE;
putname (&ldir[i].l_name, name);
seek(lfd, 0L, 2); /* append to end */
secoffs = tell(lfd) / SECTOR;
seek(lfd,0L,2); /* clear write error? */
ldir[i].l_off= secoffs;
numsecs = fcopy (ifd, lfd);
ldir[i].l_len= numsecs;
close (ifd);
}
fcopy (ifd, ofd)
int ifd, ofd;
{
int total = 0;
int i,n;
char sectorbuf[SECTOR];
while (n= read(ifd,sectorbuf,SECTOR) ) {
if (n != SECTOR) {
for (i = n; i < SECTOR; i++)
sectorbuf[i] = CTRLZ;
}
if (write(ofd,sectorbuf,SECTOR) != SECTOR)
error("write error (fcopy)");
++total;
}
return total;
}
delete (lname)
char *lname;
{
int f;
register int i;
if ((f= open(lname,0x8002)) == -1)
cant (lname);
if (nfiles <= 0)
error("delete by name only");
getdir (f);
for (i = 0; i < nslots; i++) {
if (!filarg ( getname (&ldir[i].l_name, &ldir[i].l_ext)))
continue;
ldir[i].l_stat = DELETED;
}
not_found();
if (errcnt > 0)
printf ("errors - library not updated\n");
else
putdir (f);
close (f);
}
reorg (name)
char *name;
{
int olib, nlib;
int oldsize;
register int i, j;
struct ludir odir[MAXFILES];
char tmpname[SECTOR];
for (i= 0; (i < 8) && (name[i] != '.'); i++) /* copy filename, */
tmpname[i]= name[i]; /* strip off extention, */
tmpname[i]= '\0';
strcat(tmpname,".tmp"); /* make new name, */
if ((olib= open(name,0x8002)) == -1)
cant(name);
if ((nlib= creat(tmpname,0x8002)) == -1)
cant(tmpname);
getdir(olib);
printf("Old library has %d slots\n", oldsize = nslots);
for(i = 0; i < nslots ; i++)
copymem( (char *) &odir[i], (char *) &ldir[i],
sizeof(struct ludir));
initdir(nlib);
errcnt = 0;
for (i = j = 1; i < oldsize; i++)
if( odir[i].l_stat == ACTIVE ) {
printf("Copying: %-8.8s.%3.3s\n",&odir[i].l_name, &odir[i].l_ext);
copyentry( &odir[i], olib, &ldir[j], nlib);
if (++j >= nslots) {
errcnt++;
printf("Not enough room in new library\n");
break;
}
}
close(olib);
putdir(nlib);
close (nlib);
if (errcnt == 0) {
unlink(name); /* delete orig file, */
link(tmpname,name); /* rename it, */
} else {
printf("Errors, library not updated\n");
unlink(tmpname);
}
}
copyentry( old, of, new, nf )
struct ludir *old, *new;
int of, nf;
{
register int secoffs, numsecs;
char buf[SECTOR];
new->l_stat = ACTIVE;
copymem(&new->l_name, &old->l_name, 8);
copymem(&new->l_ext, &old->l_ext, 3);
seek(of, (long) (old->l_off * SECTOR), 0);
seek(nf, 0L, 2);
secoffs = tell(nf) / SECTOR;
seek(nf,0L,2); /* clear write error? */
new->l_off= secoffs;
numsecs = old->l_len;
new->l_len= numsecs;
while(numsecs-- != 0) {
if (read(of,buf,SECTOR) != SECTOR)
error("read error");
if (write(nf,buf,SECTOR) != SECTOR)
error("write error (copyentry)");
}
}
copymem(dst, src, n)
register char *dst, *src;
register unsigned int n;
{
while(n-- != 0)
*dst++ = *src++;
}
/* ATOI() function missing from Lattice C. From Kernighan and Richie. */
atoi(s)
char s[];
{
int i,n;
n= 0;
for (i= 0; s[i] >= '0' && s[i] <= '9'; ++i)
n= 10*n + s[i]-'0';
return(n);
}
/* Missing Lattice C function: File rename
error= link(oldname,newname); */
link(old,new)
char *old,*new;
{
char fcb[36];
int i;
char *p;
for (i= 0; i < sizeof(fcb); i++) /* clear it out first, */
fcb[i]= '\0';
cvt_to_fcb(old,&fcb[1]); /* first name, */
cvt_to_fcb(new,&fcb[17]); /* new name, */
return(bdos(23,&fcb) == 0xff); /* do it. */
}
/* Convert a normal asciz string to MSDOS/CPM FCB format. Make the filename
portion 8 characters, extention 3 maximum. */
cvt_to_fcb(inname,outname)
char *inname;
char outname[];
{
char c;
int i;
for (i= 0; i < 11; i++)
outname[i]= ' '; /* clear out name, */
for (i= 0; i < 11; i++) {
if (*inname == '\0') /* if null, */
outname[i]= ' '; /* pad with blanks, */
else if (*inname == '.') { /* if a dot, */
++inname; /* skip it, */
i= 7; /* skip to extention, */
} else {
outname[i]= toupper(*inname);
++inname;
}
}
return;
}